#pragma once

#include <string>
#include <map>
#include <set>

#include "core/noncopy.h"
#include "messiah/resource/repo/repo_item.h"
#include "messiah/resource/repo/repo_res.h"
#include "repo_loader.h"

#include "messiah/mcommon.h"

namespace renderit
{
	namespace messiah
	{
		class repository : public core::noncopy
		{
		public:
			repository();

		// load from rep_loader
		public:
			void load_repos(const std::string& repos_dir, std::function<void(int)> on_completed);
			void load_repos(std::vector<std::string>& repos_path, std::function<void(int)> on_completed);

			void save();

			bool create_repo(const std::string& repo_path);
			bool copy_item(repository * other, const std::string& guid);

		public:
			uint32 replace_guid(const std::string& from_guid, const std::string& to_guid);

			uint32 remove_guid(const std::string& guid);			

		// repo item
		public:
			const std::vector<repo_item*>& get_items_by_type(EResourceType t) const 
			{
				return items_from_type_[t];
			}

			const std::vector<repo_item*>& get_items_list() const { return items_list_; }

			repo_item* get_item_by_guid(const std::string& guid) const
			{
				auto it = this->item_from_guid_.find(guid);
				if (it != this->item_from_guid_.end())
				{
					return it->second;
				}
				return nullptr;
			}

			int get_items_count() const { return items_list_.size(); }

			const std::map<std::string, std::set<repo_item*>>& get_items_from_deps() const{ return items_from_dep_guid_; }
			
		// other funcs
		public:
			void dump_info();

			const std::vector<repo_loader*>& get_loaders() const { return repo_loaders_; }
			repo_loader * get_loader(const std::string& repo_name)
			{
				for (auto& l : repo_loaders_)
				{
					if (l->repo_name() == repo_name)
					{
						return l;
					}
				}
				return nullptr;
			}

		private:
			void load_repo(const repo_loader * loader);

		// Gen MD5 use Multi-Threads
		public:
			void gen_md5s(std::function<void()> callback);

		private:
			void gen_md5_on_wt(const repo_loader * loader);
			void gen_md5_completed_on_ot(const repo_loader * loader);
			uint32 gen_md5_count_;
			std::function<void()> gen_md5_callback_;

		private:
			// items
			std::vector<repo_item*> items_list_;
			
			std::vector<repo_item*> items_from_type_[EResourceType_End + 1];

			std::map<std::string, repo_item*> item_from_guid_;

			std::map<std::string, std::set<repo_item*>> items_from_dep_guid_;
			
			// loaders
			std::vector<repo_loader*> repo_loaders_;
			uint32 repo_loading_count_;
			std::function<void(int)> repo_load_callback_;

			// stats
			uint64 fsize_;
		};
	}
}